/*
 * GameObject.h
 *
 *  Created on: 20.01.2012
 *      Author: Kirill Blinov
 *      Copyright: LGPL
 */

#ifndef GAMEOBJECT_H_
#define GAMEOBJECT_H_

#include "../BasicTypes.h"
#include "ShaderTypes.h"

/*
 * Contains information necessary for render a 3D model
 */
struct RENDER_MODEL_INFO
{
	//TODO make a proper loader directly from smd model
	RENDER_MODEL_INFO() : primitiveType(GL_TRIANGLES) {};
	RENDER_MODEL_INFO( IShaderProgram *ShaderProgram, const GLuint VertexCount, std::vector<GLushort> Indexes,
			           std::vector<TEXTURE_DESCRIPTOR> Textures ) :
	    shaderProgram(ShaderProgram), vertexCount(VertexCount), indexes(Indexes), textures(Textures),
	    indexType(GL_UNSIGNED_SHORT), primitiveType(GL_TRIANGLES) {};
	//Id of shader program the object to be rendered
	IShaderProgram                 *shaderProgram;
	GLuint                          vertexCount;
	std::vector<GLushort>           indexes;
	std::vector<TEXTURE_DESCRIPTOR> textures;

	//Offset from the buffer first vertex ( equals sum of vertices in previous models )
	UINT                    offsetInVertexBuffer;

	//usually GL_UNSIGNED_SHORT
	GLenum                  indexType;

	//Type of primitives GL_TRIANGLES for example
	GLenum                  primitiveType;
};

/*
 * Contains array of vertices and texture numbers describing a 3D model
 */
struct PURE_COMPRESSED_MODEL
{
	PURE_COMPRESSED_MODEL( std::vector<STANDART_VERTEX> Vertices, std::vector<GLushort> Indexes, std::vector<GLuint> Textures ):
		vertices(Vertices), indexes(Indexes)/*, textures(Textures)*/ {};
	std::vector<STANDART_VERTEX> vertices;
	std::vector<GLushort>        indexes;
	//Reference to structure to save offset in vertex buffer
	RENDER_MODEL_INFO           *renderInfo;
};

struct GAME_SUBOBJECT_INSTANCE
{
	GAME_SUBOBJECT_INSTANCE(){};
	GAME_SUBOBJECT_INSTANCE( RENDER_MODEL_INFO* RenderInfo, const glm::mat4 Position ) :
		                     renderInfo( RenderInfo ), position( Position ),
		                     textureDescriptors( RenderInfo->textures ), enabled(true)
	{
	}

	bool UpdateTexture( const TEXTURE_DESCRIPTOR &Texture )
	{
		bool Result = false;

		for ( std::vector<TEXTURE_DESCRIPTOR>::iterator Intit = textureDescriptors.begin(),
			  Intend = textureDescriptors.end();
			  Intit != Intend; ++Intit )
		{
			TEXTURE_DESCRIPTOR *TextureDesc = Intit.base();

			if (( !TextureDesc->alias.empty() && ( TextureDesc->alias == Texture.alias ) ) ||
				( TextureDesc->number == Texture.number ))
			{
				TextureDesc->name = Texture.name;
				if ( Texture.textureGLid > 0 )
				{
					TextureDesc->textureGLid = Texture.textureGLid;
					TextureDesc->textureType = Texture.textureType;
				}
				Result = true;
				break;
			}
		}

		return Result;
	}

	RENDER_MODEL_INFO              *renderInfo;
	//Position relatively to the center of main object
	glm::mat4                       position;

	std::vector<TEXTURE_DESCRIPTOR> textureDescriptors;

	//Matrixes for bones
	std::vector<glm::mat4>          bonesMatrixes;

	bool                            enabled;
};

/*
 * Contains game object ( set of 3D models with its world matrixes and bones )
 */
struct SUBOBJECT_WITH_CONTROLLER
{
	SUBOBJECT_WITH_CONTROLLER(){};
	SUBOBJECT_WITH_CONTROLLER( GAME_SUBOBJECT_INSTANCE *Subobject, IAnimationController* Controller ) :
		subobject(Subobject), controller(Controller)
	    {}
	GAME_SUBOBJECT_INSTANCE *subobject;
	IAnimationController    *controller;
};

struct GAME_OBJECT
{
	GAME_OBJECT(): distanceToCamera(0), translation(0.0f, 0.0f, 0.0f), orientation( 1.0f, glm::vec3(0.0f, 0.0f, 0.0f) ),
			       worldMatrix(1.0f)
	{};
	std::vector<SUBOBJECT_WITH_CONTROLLER> models;
	glm::vec3                              firstCorner;
	glm::vec3                              secondCorner;
	glm::vec3                              sphereCenter;
	float                                  sphereRadius;
	glm::gtx::quaternion::quat             orientation;
	glm::vec3                              translation;

	// Offset of model form coordinate center
	glm::mat4                              correctionMatrix;
	glm::mat4                              worldMatrix;
	float                                  distanceToCamera;
};

/*
 * All necessary information to render a frame
 */
struct FULL_FRAME_DATA
{
	std::vector<GAME_OBJECT*>  gameObjectsArray;
	std::vector<GAME_CAMERA*>  camerasArray;
	std::vector<GUI_ELEMENT*>  guiElementsArray;
	GLuint                     vertexArrayId;
	RENDER_MODEL_INFO*         guiDummy;
};

#endif /* GAMEOBJECT_H_ */
